home *** CD-ROM | disk | FTP | other *** search
/ Aminet 1 (Walnut Creek) / Aminet - June 1993 [Walnut Creek].iso / usenet / sources / volume2 / dos / virusx21.1 < prev   
Text File  |  1988-12-12  |  49KB  |  1,793 lines

  1. Path: xanth!ames!husc6!mailrus!ulowell!page
  2. From: page@swan.ulowell.edu (Bob Page)
  3. Newsgroups: comp.sources.amiga
  4. Subject: v02i096:  virusx - virus exterminator v2.10
  5. Message-ID: <10671@swan.ulowell.edu>
  6. Date: 12 Dec 88 21:45:39 GMT
  7. Organization: University of Lowell, Computer Science Dept.
  8. Lines: 1782
  9. Approved: page@swan.ulowell.edu
  10.  
  11. Submitted-by: kim@uts.amdahl.com (Kim E. DeVaughn)
  12. Posting-number: Volume 2, Issue 96
  13. Archive-name: dos/virusx210.1
  14.  
  15. #    This is a shell archive.
  16. #    Remove everything above and including the cut line.
  17. #    Then run the rest of the file through sh.
  18. #----cut here-----cut here-----cut here-----cut here----#
  19. #!/bin/sh
  20. # shar:    Shell Archiver
  21. #    Run the following text with /bin/sh to create:
  22. #    Announcement
  23. #    Makefile
  24. #    README
  25. #    VirusX.doc
  26. #    _main.c
  27. #    virusx.c
  28. #    vx.asm
  29. # This archive created: Mon Dec 12 16:39:49 1988
  30. cat << \SHAR_EOF > Announcement
  31. This version has mostly WorkBench bug fixes.  It no longer crashes when
  32. run from WorkBench and then quit.  It lets you specify window size on
  33. the command line.  Allows you to bring up a CLI or WShell at any time.
  34.  
  35. Also recognizes a new variant of the Byte Warrior virus.
  36.  
  37. SHAR_EOF
  38. cat << \SHAR_EOF > Makefile
  39. MODULES = virusx.o vx.o detach.o
  40. CFLAGS = -n +l -s -DNDEBUG
  41. LINKFLAGS = +cdb
  42.  
  43. virusx : $(MODULES)
  44.     ln -g -o virusx $(LINKFLAGS) $(MODULES) -lc32 
  45.  
  46. vx.o : vx.asm
  47.     as -o vx.o vx.asm
  48.  
  49. detach.o:    _main.c
  50.     cc -n +bl +x3,5 -DDETACH -o $@ _main.c
  51. SHAR_EOF
  52. cat << \SHAR_EOF > README
  53. IMPORTANT difference between this version and previous ones:
  54. DO NOT USE RUNBACK TO RUN VIRUSX.  VirusX has the equivalent
  55. of RunBack built in, just put "VirusX" alone on your command
  56. line (or in your startup sequence).  VirusX WILL work with
  57. RunBack, but will NOT let you pop up a CLI properly from
  58. runback.
  59.  
  60. For those of you who have been following the VirusX Saga:
  61.  
  62. The reason for the V2.00/2.01 woes was a bug in the Manx startup
  63. module.  I've redone the startup module and it works, and is also
  64. a fair bit smaller - this is about 1.5K or so smaller than V2.01.
  65.  
  66. No new viruses.
  67.  
  68. One new function (Two actually):
  69.  
  70. Clicking in the VirusX window and hitting P will pop up a new CLI window.
  71. Clicking in the VirusX window and hitting W will open a new WSHell if
  72. you happen to have Wshell.  (If you don't, well, anything in the C
  73. directory named "NewWSH" will get called when you hit W).
  74.  
  75. Due to the way the startup module works, these new CLI windows do not
  76. have a "Current Directory" - ie, pop up a CLI and type "CD", it
  77. will say "DF0:".  I don't know of any way around this.
  78.  
  79. Let me know if this version crashes on you at any point - It sure shouldn't!
  80.  
  81.     ...Steve
  82. SHAR_EOF
  83. cat << \SHAR_EOF > VirusX.doc
  84.  
  85.                   [0;3;31;40m-[0;1;33;40mVirusX[31;40m-[0;31;40m
  86.  
  87.               [0;1mby Steve Tibbett[0;31;40m
  88.  
  89.  
  90.    [0;3;31;40m- The Complete Virus Removal System! -[0;31;40m
  91.  
  92. VirusX - Fourth in a growing line of "X-Utilities".
  93.  
  94. REMEMBER: STUFF NEW TO THE LATEST VERSION IS AT THE _END_ OF THIS
  95. FILE!
  96.  
  97. Version Notes:
  98. --------------
  99. Version Notes are now in the VirusX.C file, as is information on
  100. some of the viruses.
  101.  
  102.  
  103. Amiga Viruses have been following us around for some time now, and I
  104. think it's about time we got rid of it for good.
  105.  
  106. There are a number of CLI-based Virus Checkers out there, which do their
  107. job just fine, but if you're not into using CLI, what do you do? You use
  108. VirusX!
  109.  
  110. Please, I encourage you to give this program to anybody who might have
  111. the virus.  Including your local dealer - some of the dealers in this
  112. area have the virus all over their disks, which they allow customers to
  113. copy, and they don't do anything about it because they don't know how. 
  114. VirusX makes it extremely simple.
  115.  
  116. You can put VirusX in your Startup-Sequence.  When run, it will open a
  117. small window so you know it's there (and it will display the occasional
  118. message in it).  Whenever a disk is inserted into any of the 3.5"
  119. drives, that disk is automagically checked for the SCA virus, and also
  120. checked to see if it's boot sector is "Standard".  If the disk has a
  121. nonstandard boot sector, it is either a new form of virus which I don't
  122. know about yet, or it is a commercial program which uses the boot block
  123. for  something constructive (like booting their game).
  124.  
  125. If VirusX finds a boot block it is suspicious about, it will present the
  126. user with a requester either warning him that the disk has the SCA virus
  127. (or any other current viruse), or telling him that the boot code is
  128. nonstandard.  In either case, he is given the option to either ignore
  129. it, or to Remove it.
  130.  
  131. If the user selects Remove, after he says he's SURE he wants to
  132. rewrite the disk's boot sector (Remember: Never rewrite the boot
  133. sector of a commercial program unless you KNOW that program doesn't
  134. use it for something else.  If the program gives you the AmigaDOS
  135. window before running, you know it is safe to repair that disk.).  
  136. The boot code written back to the disk by VirusX is the same boot code
  137. that the AmigaDOS INSTALL command (and it's compatible counterpart on
  138. one of the fish disks) uses.  
  139.  
  140. If you click in the little "VirusX" window, and type a number from 0
  141. to 3, (Corresponding to the drive # you would like to look at), VirusX
  142. will resize it's window to fit in the ASCII text of these two blocks,
  143. and allow you to view it.  When you run across a "Nonstandard Boot
  144. Block", you can now check and see if the boot block is some sort of
  145. new Virus (Assuming that the author of the Virus left a string in it)
  146. as you will see something like "Revenge Virus 1.2G" or whatever string
  147. that identifies the virus.  Note that not all viruses have text strings
  148. in them, so don't use this method alone to determine whether an 
  149. unknown boot block is a virus or not.  
  150.  
  151. Also, you can check to see which strain of the SCA virus you have
  152. (VirusX will report "an SCA virus", but will not tell you if it is the
  153. "LSD" virus, or the "Zorro/Willow" virus or whatever new ones may
  154. appear).
  155.  
  156. Generally, if boot code is capable of writing itself back to a different
  157. disk than the one it was loaded from, it is a virus.
  158.  
  159. Keystrokes:  0, 1, 2, 3, will show you the boot block of whatever drive
  160. you select (0 would be DF0:, say), I will show you the Info window, and
  161. P will get you a new CLI.  C will cause VirusX to  re-check all inserted
  162. disks.  To use the keystrokes, click in the main VirusX window and type
  163. away.
  164.  
  165. If you run across a strain of the virus, or any other virus that VirusX
  166. doesn't specifically warn of, PLEASE send me a copy of a disk with that
  167. virus on it!  I want to keep VirusX current, and to do so, I need the
  168. viruses.
  169.  
  170. Of course, there are those of you who are thinking that I am some nut
  171. case trying to spread my own virus hidden under the guise of a virus
  172. checker.  Well, just for you, I've included the C source code.  Please,
  173. if you don't trust me, don't discard a useful utility as untrustworthy
  174. for no reason, CHECK THE SOURCE!  Recompile it if you think I'm trying
  175. to slip a fast one on you.  I just want to see the virus out of all of
  176. our lives.
  177.  
  178. I want feedback on this!  Send me a letter!  This program is
  179. Copyrighted, but is freely redistributable (It's NOT Shareware).  Do
  180. what you want with it, but  Please don't use it for evil purposes. 
  181. That's what I'm trying to prevent.  (If your conscience is compelling
  182. you to send me something, send me an original game you're bored
  183. with... It won't cost you anything, and it'll keep me busy for a 
  184. few hours (or more...).
  185.  
  186. My address:
  187.  
  188.     Steve Tibbett
  189.     2710 Saratoga Pl. #1108
  190.     Gloucester, Ontario
  191.     K1T 1Z2
  192.  
  193.     My BBS: OMX BBS, 613-731-3419.
  194.  
  195.     I can be reached on BIX as "s.tibbett" and on People/Link
  196.     as "SteveX".  I'm also on Compuserve, but with their dumb
  197.     numbering system, I can never remember who I am.
  198.  
  199.  
  200. ---------------------------------------------------------------
  201.  
  202. BYTE BANDIT VIRUS:
  203.  
  204. What the Byte Bandit virus does is once it's in
  205. memory, it copies itself to just above the high memory
  206. pointer on the first hunk of RAM it can find (Which means
  207. it's not always in the same place), wedges itself into the
  208. Interrupt Server chain, into the Trackdisk.device's vectors,
  209. and creates itself a Resident structure so it can hang
  210. around after reboot.
  211.  
  212. It watches EVERY disk inserted, and will write itself to ANY
  213. bootable disk that is inserted!  This one can spread like
  214. wildfire - every disk you insert into your external drive during
  215. a session with this Virus loaded will result in all those disks
  216. being infected.  Ouch.
  217.  
  218. Also, if you Install a disk while this virus is going, it will  just
  219. copy itself back to the disk - which is why it has to be wiped it from
  220. memory.
  221.  
  222. When VirusX finds this virus on a disk, it will also display a "Copy
  223. Count" which is the number of disks that have been infected by that
  224. "Branch" on the "Tree" that the virus is on -  If you infect a disk with
  225. your copy, and your copy is number 300, then that copy will be #301.  If
  226. he infects somebody,  that will be #302, but on YOUR copy, two
  227. infectations down the line, there will be another #302... Anyways, the
  228. copy count on MY Byte Bandit virus is #879... 
  229.  
  230. Note that VirusX will check RAM for this virus as well as the disk. 
  231. This was necessary as you can tell from the description above.
  232.  
  233. Special thanks must go here to Dave Hewett, who, 2 days after I gave him
  234. a copy of the virus, gave me a printed, commented disassembly of the
  235. virus with meaningful labels and everything I needed to stomp it -
  236. Thanks Dave!
  237.  
  238. Thanks must also go to Bruce Dawson of CygnusSoft Software, who went to
  239. the trouble of being the First person to send me this Virus.  (As of
  240. yet, he's also the ONLY person - Geez, folks, I need YOUR help to do
  241. this too, eh?)
  242.  
  243.  
  244. REVENGE VIRUS:
  245.  
  246. What this virus does, is everything that the Byte Bandit virus does,
  247. PLUS, after infecting a disk, it will wait one  minute after every
  248. reboot, and change your mouse pointer  into an image of a certain part
  249. of the Male anatomy. 8-)
  250.  
  251. I think the reason this virus is called the "Revenge" virus is because
  252. it looks specifically for the Byte Bandit and for the SCA Virus.  If
  253. it finds either of these, it Rigs THAT virus so that it will CRASH the
  254. machine unless THIS virus is loaded first.  Note that I might be wrong
  255. about this - that's the way it looks from the disassembly, but I don't
  256. have an SCA virus here to  test it with.   I tried it with the Byte
  257. Bandit, and it didn't seem to do anything like this - but be warned,
  258. in case it pops up later or something.
  259.  
  260. He stays in RAM via changing the CoolCapture vector to point to his
  261. own code.  He then intercepts the DoIO() call and watches for any
  262. attempts to rewrite or to read the boot block and acts accordingly. 
  263. He also has an interrupt around counting VBlanks until it's time to
  264. bring up his sicko pointer.
  265.  
  266. To get this virus out of memory is Simple - Hold down the Joystick
  267. button (Plug a joystick into port 2, and hold down the button while
  268. you are rebooting), and the screen will briefly turn RED during the
  269. boot, and it's out of memory. (If you hold down Joystick button AND
  270. mouse button, it will half-remove himself from RAM and turn the screen
  271. Blue)
  272.  
  273. VirusX will alert you if the virus is present in RAM and will render
  274. it helpless in RAM before telling you about  it.  It will also report
  275. it's presence on disk.  
  276.  
  277. I'd like to thank Lars Wilkund for being the first (And only so far)
  278. person to send me this virus on disk.  Lasse is part of a Swedish users
  279. group with over 700 members!
  280.  
  281. BYTE WARRIOR VIRUS:
  282.  
  283. The Byte Warrior Virus is a lot like the Byte Bandit virus, except
  284. it is not designed to hurt anything - it will start an "Alarm"
  285. sound if it sees another virus (or at least I think it does - 
  286. it hasn't for me), but other than that, it will write itself to
  287. any disk inserted.  There is also a hidden message in it, asking us
  288. to spread it around and not to erase it.  Ya, right.
  289.  
  290.  
  291. NORTH STAR VIRUS:
  292.  
  293. It's a virus itself that alerts you to other ones - 
  294. I think this sort of idea is stupid because it can do just as 
  295. much damage as the rest of them.
  296.  
  297. One new virus showed up for this version, the "Obelisk Softworks
  298. Crew" virus.  It was sent to me by Jason Allen Smith.  Thanks, 
  299. Jason!
  300.  
  301. Other changes this version - it's now a bunch smaller (again!) thanks
  302. to a bit of a rewrite in assembler, and some reorganization.
  303.  
  304.  
  305. SCA Virus:
  306.  
  307. This is the original.  It just sits in RAM writing itself to any
  308. disk you boot off of.  You can get it out of memory by either running
  309. VirusX, or holding down the left mouse button while you reboot
  310. the machine (The machine will flash the screen green once it's
  311. truly gone).
  312.  
  313. -------------------------------------------------------------------
  314.  
  315. I'd like to thank Lars Wilklund, Jason Allen Smith, Bruce Dawson,
  316. Robb Bowns (sorry, Rob, I can't remember how your last name goes,
  317. I think that's it), and all the others who have sent me disks
  318. whom I cannot remember.  Sorry I don't answer mail as quickly or
  319. as often as I'd like, I have very little time these days.
  320.  
  321. There are MORE viruses out there!  Please, send them to me!
  322.  
  323.     ...Steve
  324.  
  325. SHAR_EOF
  326. cat << \SHAR_EOF > _main.c
  327. /* Copyright (C) 1986,1987 by Manx Software Systems, Inc. */
  328.  
  329. /*
  330.  *    This is common startup code for both the CLI and the WorkBench.
  331.  *    When called from the WorkBench, argc is 0 and argv points to a
  332.  *    WBStartup type of structure.
  333.  */
  334.  
  335. #include <fcntl.h>
  336. #include <exec/alerts.h>
  337. #include <exec/memory.h>
  338. #include <libraries/dosextens.h>
  339. #include <workbench/startup.h>
  340. #include <functions.h>
  341.  
  342. extern long _savsp, _stkbase;
  343.  
  344. extern int errno;
  345. extern int Enable_Abort;
  346.  
  347. extern int _argc, _arg_len;
  348. extern char **_argv, *_arg_lin;
  349. extern struct WBStartup *WBenchMsg;
  350.  
  351. extern struct _dev *_devtab;
  352. extern short _numdev;
  353.  
  354. _main(alen, aptr)
  355. long alen;
  356. char *aptr;
  357. {
  358.     register struct Process *pp, *_FindTask();
  359.     void *_OpenLibrary(), *_GetMsg(), *_AllocMem();
  360.     long _Input(), _Output(), _Open();
  361.  
  362. #ifdef DETACH
  363.     void do_detach();
  364.  
  365.     do_detach(&alen, &aptr);
  366. #endif
  367.  
  368.     if ((_devtab = _AllocMem(_numdev*(long)sizeof(struct _dev),
  369.                                                     MEMF_CLEAR)) == 0) {
  370.         Alert(AG_NoMemory, 0L);
  371. #asm
  372.         move.l    __savsp,sp        ;get back original stack pointer
  373.         rts                        ;and exit
  374. #endasm
  375.     }
  376.  
  377.     _devtab[0].mode = O_RDONLY;
  378.     _devtab[1].mode = _devtab[2].mode = O_WRONLY;
  379.  
  380.     _stkbase = _savsp - *((long *)_savsp+1) + 8;
  381.     *(long *)_stkbase = 0x4d414e58L;
  382.  
  383.     pp = _FindTask(0L);
  384. #ifdef DETACH
  385.     if (alen) {
  386. #else
  387.     if (pp->pr_CLI) {
  388. #endif
  389.         _cli_parse(pp, alen, aptr);
  390.         Enable_Abort = 1;
  391. #ifndef DETACH
  392.         _devtab[0].mode |= O_STDIO;        /* shouldn't close if CLI */
  393.         _devtab[1].mode |= O_STDIO;
  394. #endif
  395.     }
  396.  
  397.     else {
  398.         _WaitPort(&pp->pr_MsgPort);
  399.         WBenchMsg = _GetMsg(&pp->pr_MsgPort);
  400.         if (WBenchMsg->sm_ArgList)
  401.             _CurrentDir(WBenchMsg->sm_ArgList->wa_Lock);
  402.         /*_wb_parse(pp, WBenchMsg);*/
  403.         _argv = (char **)WBenchMsg;
  404.     }
  405.     _devtab[0].fd = _Input();
  406.     if (_devtab[1].fd = _Output())
  407.         _devtab[2].fd = _Open("*", MODE_OLDFILE);
  408.     main(_argc, _argv);
  409.     exit(0);
  410. }
  411.  
  412. #ifdef DETACH
  413. extern long _stack, _priority, _BackGroundIO;
  414. extern char *_procname;
  415. BPTR _Backstdout = 0;
  416. extern struct FileLock *_detach_curdir;
  417. extern char *_detach_name;
  418. static long _alen = 0;
  419. static char *_aptr = 0;
  420.  
  421. static void
  422. do_detach(alen, aptr)
  423. long *alen;
  424. char **aptr;
  425. {
  426.     register struct Process *pp, *_FindTask();
  427.     void *sav, *_OpenLibrary(), *_GetMsg(), *_AllocMem();
  428.     long _Open();
  429.     register unsigned short c;
  430.     register char *cp;
  431.     register struct CommandLineInterface *cli;
  432.     register long l;
  433.     long *lp;
  434.     struct MemList *mm;
  435.     struct FileLock *CurrentDir();
  436.  
  437.     pp = _FindTask(0L);
  438.     if (pp->pr_CLI) {            /* first time through!! */
  439.         CurrentDir(_detach_curdir = CurrentDir(0L));
  440.         _detach_curdir = DupLock(_detach_curdir);
  441.  
  442.         cli = (struct CommandLineInterface *) ((long)pp->pr_CLI << 2);
  443.         l = cli->cli_Module;
  444.         if ((sav = _OpenLibrary(DOSNAME, 33L)) == 0) {
  445.  
  446.             lp = (long *)*((long *)*((long *)*((long *)*((long *)
  447.                                             _savsp+2)+1)-3)-3)+107;
  448.             if (*lp != cli->cli_Module)
  449.                 exit(100);
  450.         }
  451.         else {
  452.             _CloseLibrary(sav);
  453.             lp = 0;
  454.         }
  455.         if (lp)
  456.             *lp = 0;
  457.         if (_stack == 0)
  458.             _stack = cli->cli_DefaultStack * 4;
  459.         if (_BackGroundIO)
  460.             _Backstdout = (BPTR)_Open("*", MODE_OLDFILE);
  461.         _alen = *alen;
  462.         _aptr = _AllocMem(_alen, 0L);
  463.         movmem(*aptr, _aptr, (int)_alen);
  464.         cp = (char *)((long)cli->cli_CommandName << 2);
  465.         _detach_name = AllocMem((long)cp[0]+1, 0L);
  466.         movmem(cp, _detach_name, cp[0]+1);
  467. #asm
  468.         move.l    __savsp,-(sp)
  469. #endasm
  470.         CreateProc(_procname, _priority, l, _stack);
  471.         cli->cli_Module = 0;
  472. #asm
  473.         move.l    (sp)+,sp
  474.         move.l    #0,d0
  475.         rts
  476. #endasm
  477.     }
  478.     else if (_alen && strcmp(pp->pr_Task.tc_Node.ln_Name, _procname) == 0) { /* second time */
  479.         lp = (long *)((long)pp->pr_SegList << 2);
  480.         lp = (long *)(lp[3] << 2);
  481.         sav = lp;
  482.         c = 2;
  483.         while (lp) {
  484.             lp = (long *)(*lp << 2);
  485.             c++;
  486.         }
  487.         mm = _AllocMem((long)sizeof(struct MemList)+
  488.                             (c-1)*sizeof(struct MemEntry), 0L);
  489.         lp = sav;
  490.         mm->ml_NumEntries = c;
  491.         c = 0;
  492.         while (lp) {
  493.             mm->ml_me[c].me_Addr = (APTR)lp - 1;
  494.             mm->ml_me[c].me_Length = lp[-1];
  495.             lp = (long *)(*lp << 2);
  496.             c++;
  497.         }
  498.         mm->ml_me[c].me_Addr = (APTR)_aptr;
  499.         mm->ml_me[c++].me_Length = _alen;
  500.         mm->ml_me[c].me_Addr = (APTR)_detach_name;
  501.         mm->ml_me[c++].me_Length = _detach_name[0] + 1;
  502.  
  503.         AddTail(&((struct Task *)pp)->tc_MemEntry, mm);
  504.  
  505.         CurrentDir(_detach_curdir);
  506.  
  507.         pp->pr_COS = _Backstdout;
  508.  
  509.         *alen = _alen;
  510.         *aptr = _aptr;
  511.     }
  512. }
  513. #endif
  514.  
  515. SHAR_EOF
  516. cat << \SHAR_EOF > virusx.c
  517. /************************************************************************/
  518. /*                                    */
  519. /*                                    */
  520. /*                                VirusX                       */
  521. /*                                    */
  522. /*                 by Steve Tibbett                */
  523. /*                                    */
  524. /*                                    */
  525. /*        Please - if you find a new virus, Send me a copy!    */
  526. /*        (And warn me it's on the disk!).  I want to keep    */
  527. /*        this program current.  (Feel free to put something    */
  528. /*        neat on the disk also!)                    */
  529. /*                                    */
  530. /*    Created with Aztec C V3.6a using 32 bit ints, my makefile is    */
  531. /*      included.  Also included is a new _main.c file, which is my     */
  532. /*      startup code.  It's basically a modified version of the Manx    */
  533. /*      _main.c, in that it doesn't do the CLI parsing, doesn't set     */
  534. /*      stdin or stdout or whatever, but it does detach from the CLI    */
  535. /*      properly (and shouldn't crash when run from WB.                 */
  536. /*                                    */
  537. /************************************************************************/
  538. /*                                    */
  539. /*  History:                                */
  540. /*  --------                                */
  541. /*    April '88 or so:  V1.0 written and released.            */
  542. /*     A few days later:  V1.01 released.  V1.0 wrote garbage to the    */
  543. /*                        disk if it was write protected then fixed.    */
  544. /*          27-March-88:  V1.2 released.  V1.2's purpose in life was    */
  545. /*                        to deal with the Byte Bandit virus.           */
  546. /*                        (Actually, it's well after midnight - make    */
  547. /*                        that March 28th. :)                           */
  548. /*          28-March-88:  Oops, V1.2 was 3K or so bigger than it needed */
  549. /*                        to be.  Fix it, release v1.21.                */
  550. /*           15-June-88:  V1.3, V1.2 cleaned up and made smaller.       */
  551. /*            8-July-88:  V1.4.  Revenge virus checking, Viewbooting,   */
  552. /*                        check for SCA in RAM, more cleaning up.       */
  553. /*           24-July-88:  V1.5, only change was the addition of the     */
  554. /*                        Byte Warrior virus.                           */
  555. /*             1-Aug-88:  V1.6 (busy week), Dan Mosedale sent me the    */
  556. /*                        Northstar Virus.  Nuked it.                   */
  557. /*            18-Aug-88:  V1.7 - after 2 weeks off, got the Obelisk     */
  558. /*                        Softworks crew virus.                         */
  559. /*     a few days later:  V1.71, can't remember why.                    */
  560. /*   September Sometime:  Biggest mistake of my life, released V2.0.    */
  561. /*         3 days later:  Bigger mistake:  Released V2.01 - which was   */
  562. /*                        2.0 with another bug added.  Argh.            */
  563. /*             6-Nov-88:  Finally got some time to clean things up,     */
  564. /*                        check out the startup code bugs, clean up the */
  565. /*                        docs and source, and release V2.1.  There     */
  566. /*                        haven't been any new viruses in about a month */
  567. /*                        now, but I hear one or two are on the way.    */
  568. /*                                    */
  569. /************************************************************************/
  570. /*                                    */
  571. /*  Viruses Dealt With:                            */
  572. /*  -------------------                            */
  573. /*                                    */
  574. /*     SCA        - The SCA is the simplest virus to deal with,   */
  575. /*               as it's not actually DOING anything except    */
  576. /*              hiding in memory, until you reboot.       */
  577. /*              We just look at CoolCapture and fix it to get */
  578. /*              it out of RAM.                */
  579. /*                                    */
  580. /*    Byte Bandit    - The Byte Bandit virus takes the DoIO() vector */
  581. /*              and redirects it through itself.  Thus, any   */
  582. /*              attempt to read or write the boot block (ie,  */
  583. /*               AmigaDOS trying to figure out what kind of    */
  584. /*               disk it is) results in the BB writing itself  */
  585. /*              onto that disk.  VirusX couldn't just rewrite */
  586. /*              the boot block, we have to get him out of RAM */
  587. /*                first.  This virus also has an interrupt that */
  588. /*                        crashes the machine every 5 minutes or so     */
  589. /*                        after it's infected a few of your disks.  Ow. */
  590. /*              It stays in memory not via the Capture        */
  591. /*                        vectors, but by a Resident module.           */
  592. /*                                    */
  593. /*    Revenge        - Basically, a Byte Bandit clone except it will */
  594. /*              bring up an obscene pointer a few minutes    */
  595. /*              after you reboot.  We treat it much like the  */
  596. /*              byte bandit.                    */
  597. /*                                    */
  598. /*    Byte Warrior     - Jumps right into 1.2 Kickstart.  Won't work   */
  599. /*               under 1.3.  Hangs around via Resident struct, */
  600. /*              doesn't do any damage.            */
  601. /*                                    */
  602. /*    North Star    - Like SCA, hangs around via CoolCapture,    */
  603. /*              killing CoolCapture kills the North Star.     */
  604. /*                                    */
  605. /*    Obelisk Softworks Crew                         */
  606. /*                      - Hangs around via CoolCapture, also        */
  607. /*              watches reads of DoIO() (but doesn't        */
  608. /*              infect EVERY disk - onlyt ones you boot    */
  609. /*              off of)                    */
  610. /*                                    */
  611. /************************************************************************/
  612.  
  613. #include <stdio.h>
  614. #include <exec/types.h>
  615. #include <intuition/intuition.h>
  616. #include <devices/bootblock.h>
  617. #include <devices/trackdisk.h>
  618. #include <exec/execbase.h>
  619. #include <libraries/dos.h>
  620.  
  621. /********************************************************************/
  622. /*  These are for the Manx detach module, which I've modified but   */
  623. /*  I left these intact.  Stack, Priority, BackgroundIO (always 0!),*/
  624. /*  and the name of your process.                    */
  625. /********************************************************************/
  626. long _stack         = 8000;
  627. long _priority         = 0;
  628. long _BackGroundIO     = 0;
  629. char *_procname     = "VirusX 2.10";
  630.  
  631.  
  632. /********************************************************************/
  633. /* These string constants are used in multiple places, and thus     */
  634. /* save bytes by having only one copy of them.                      */
  635. /********************************************************************/
  636. char TDName[]         = "trackdisk.device";
  637. char copystring[]     = "(Copy Count on this disk: %d)";
  638. char ITBodyText[80];
  639. char VN_OBELISK[]     = "Obelisk";
  640. char VN_NORTHSTAR[]     = "North Star";
  641. char VN_SCA[]         = "SCA";
  642. char VN_BYTEBANDIT[]     = "Byte Bandit";
  643. char VN_BYTEWARRIOR[]     = "Byte Warrior";
  644. char VN_REVENGE[]     = "Revenge";
  645. char CaptureStr[]     = "Capture is pointing at $";
  646. char text[]         = "DF6: Boot Sectors";
  647. char TITLETEXT[]     = "VirusX 2.10 by Steve Tibbett";
  648.  
  649.  
  650.  
  651. /********************************************************************/
  652. /* These counters are for the Info window, one for each virus.      */
  653. /********************************************************************/
  654. int     ObeliskCount;
  655. int     NorthStarCount;
  656. int     SCACount;
  657. int     ByteBanditCount;
  658. int     ByteWarriorCount;
  659. int     RevengeCount;
  660.  
  661.  
  662. /*******************************************************************/
  663. /*  Miscellaneous variables.                       */
  664. /*******************************************************************/
  665. int     ChangeCount[4];            /* TD_CHANGECOUNT for 4 drives     */
  666. int     LastSum;            /* Used in the checksumming     */
  667. int     error;                /* sort of a temporary variable */
  668. char     WindowBig;            /* TRUE if the window is big    */
  669. struct     Port *diskport;            /* trackdisk's port.            */
  670. struct     IOStdReq *diskreq;        /* trackdisk's IOStdReq         */
  671. int    DisksChecked, DisksInstalled;     /* for title bar info           */
  672. int     VirusBase;            /* ick, whatta name!         */
  673. char     FromCLI;            /* True if run from CLI        */
  674.  
  675. struct IntuitionBase     *IntuitionBase;    /* For Library Bindings        */
  676. struct GfxBase         *GfxBase;
  677. struct Window         *Window;
  678. struct IntuiMessage     *Message;
  679.  
  680. int Keepgoing;        /* A flag.  It's false when we want out.     */
  681. int x, y, i;        /* Left over from my using Basic         */
  682.  
  683. struct NewWindow NewWindow = 
  684.     {
  685.     128,0,    309,10,     0,1,        
  686.     DISKINSERTED | CLOSEWINDOW | VANILLAKEY | NEWSIZE | MOUSEBUTTONS,    /* IDCMP Flagz */
  687.     WINDOWDRAG | WINDOWDEPTH | RMBTRAP | WINDOWCLOSE | NOCAREREFRESH, /* Windo Flagz */    
  688.     NULL, NULL,TITLETEXT,
  689.     NULL,NULL,0,0,0,0,WBENCHSCREEN,    
  690.     };
  691.  
  692. struct RastPort *RP;
  693.  
  694. #define BSIZE 40    /* Ha!  I'm not telling what this is! */
  695.  
  696.  
  697. /*******************************************************************/ 
  698. /*  diskbuffer is where all disk io goes to.  it's 3*512 rather    */
  699. /*  than 2*512, because I believe one of the viruses watches for   */
  700. /*  reads of 1024 bytes, so I'm just being safe.           */
  701. /*******************************************************************/ 
  702. UBYTE diskbuffer[3*512];
  703.  
  704.  
  705. /************************************************************************/
  706. /* Warning messages.  These messages get modified before being          */
  707. /* displayed (Unless you DO have a DF9:)                                */
  708. /************************************************************************/
  709. char TEXTPTR[] = "Danger:  The disk in DF9: is";
  710. char NBCTEXT[] = "Danger:  The disk in DF9: has";  /* What a waste, eh? */
  711. char CopyText[40];
  712.  
  713. /*************************************************************************/
  714. /*   This is a byte by byte copy of working boot block code.  Check it   */
  715. /*   out if you like.  This is what gets written back to the disk when   */ 
  716. /*   you ask VirusX to fix a disk.                          */
  717. /*************************************************************************/
  718. unsigned char bootblock[] = { 'D', 'O', 'S', 0, 
  719. 0xc0, 0x20, 0x0f, 0x19, 0x00, 0x00, 0x03, 0x70, 0x43, 0xfa, 0x00, 0x18, 
  720. 0x4e, 0xae, 0xff, 0xa0, 0x4a, 0x80, 0x67, 0x0a, 0x20, 0x40, 0x20, 0x68, 
  721. 0x00, 0x16, 0x70, 0x00, 0x4e, 0x75, 0x70, 0xff, 0x60, 0xfa, 0x64, 0x6f,
  722. 0x73, 0x2e, 0x6c, 0x69, 0x62, 0x72, 0x61, 0x72, 0x79, 0x00, 0x00, 0x00,
  723. 0x00, 0x00};
  724.  
  725.  
  726.  
  727.  
  728. /********************************************************************/
  729. /*  My intuition defines.  There's lots of 'em - theyre self explan.*/
  730. /********************************************************************/
  731.  
  732. struct TextAttr TxtAt_Plain = 
  733.     {    
  734.     "topaz.font", 8, FS_NORMAL, FPF_ROMFONT
  735.     };
  736.  
  737. /***  Non SCA warning requester IntuiText's ***/
  738.  
  739. struct IntuiText Body2 = 
  740.     { 
  741.     0, 1,  JAM2, 20,18, &TxtAt_Plain, "Nonstandard Boot Code!", NULL 
  742.     };
  743.  
  744. struct IntuiText Body1 = 
  745.     { 
  746.     0,1, JAM2, 20, 8, &TxtAt_Plain, (UBYTE *)NBCTEXT, &Body2 
  747.     };
  748.  
  749. /*-  This one says "The disk in DFx: is"  -*/
  750.  
  751. struct IntuiText GenericFirstBody = 
  752.     {
  753.     0,1, JAM2, 20,8,&TxtAt_Plain, (UBYTE *)TEXTPTR, 0 
  754.     };
  755.  
  756.  
  757. /***** Generic IntuiTexts used as of V1.7 ******/
  758.  
  759. struct IntuiText GenericDiskBody = 
  760.     {
  761.     0,1, JAM2, 20,18, &TxtAt_Plain,ITBodyText, &GenericFirstBody 
  762.     };
  763.  
  764. struct IntuiText SCAPos = 
  765.     {
  766.     0,1, JAM2, 7,3, &TxtAt_Plain, "Remove it", NULL 
  767.     };
  768.  
  769. struct IntuiText Repair = 
  770.     {
  771.     0,1, JAM2, 7,3, &TxtAt_Plain, "Repair it", NULL 
  772.     };
  773.  
  774. struct IntuiText SCANeg = 
  775.     {
  776.     0,1, JAM2, 7,3, &TxtAt_Plain, "Ignore it", NULL 
  777.     };
  778.  
  779. /*  Special cases (display copy count) */
  780.  
  781. /***** BBANDIT Requester IntuiText's ******/
  782. struct IntuiText BBDiskbody2 = 
  783.     {
  784.     0,1, JAM2, 20,30, &TxtAt_Plain, CopyText, &GenericFirstBody 
  785.     };
  786.  
  787. struct IntuiText BBDiskbody = 
  788.     {
  789.     0,1, JAM2, 20,18, &TxtAt_Plain, ITBodyText, &BBDiskbody2
  790.     };
  791.  
  792. /***** Revenge on Disk Requester IntuiText's ******/
  793. struct IntuiText RevDiskbody3 = 
  794.     {
  795.     0,1, JAM2, 20,30, &TxtAt_Plain, CopyText, &GenericFirstBody 
  796.     };
  797.  
  798. struct IntuiText RevDiskbody = 
  799.     {
  800.     0,1, JAM2, 20,18, &TxtAt_Plain,(UBYTE *) "infected with the -Revenge- VIRUS!", &RevDiskbody3
  801.     };
  802.  
  803.  
  804. /***** Generic Notice - Removed from Memory ****/
  805. struct IntuiText GRB3 = 
  806.     {
  807.     0,1, JAM2, 20,18, &TxtAt_Plain,(UBYTE *) "in memory, and is now disabled.  See the", NULL
  808.     };
  809.  
  810. struct IntuiText GRB2 = 
  811.     {
  812.     0,1, JAM2, 20,28, &TxtAt_Plain,(UBYTE *) "documentation for more information!", &GRB3 
  813.     };
  814.  
  815. struct IntuiText GenericRAMBody = 
  816.     {
  817.     0,1, JAM2, 20, 8, &TxtAt_Plain, ITBodyText, &GRB2 
  818.     };
  819.  
  820. struct IntuiText BBMPos = 
  821.     {
  822.     0,1, JAM2,  7, 3, &TxtAt_Plain, " Thanks! ", NULL 
  823.     };
  824.  
  825. struct IntuiText Mem3 = 
  826.     {
  827.     0,1, JAM2, 20,28, &TxtAt_Plain,(UBYTE *) "some other utility is the cause of it.", NULL
  828.     };
  829.  
  830. struct IntuiText Mem2 = 
  831.     {
  832.     0,1, JAM2, 20,18, &TxtAt_Plain,(UBYTE *) "This could mean a new Virus is in RAM, or", &Mem3
  833.     };
  834.  
  835. struct IntuiText Mem1 = 
  836.     {
  837.     0,1, JAM2, 20, 8, &TxtAt_Plain, 0 , &Mem2
  838.     };
  839.  
  840.  
  841. /***** Write Protect Error Requester IntuiText's ******/
  842. struct IntuiText ERRBody2 = 
  843.     {
  844.     0,1, JAM2, 20,18, &TxtAt_Plain,(UBYTE *) "Write Protected.", NULL 
  845.     };
  846.  
  847. struct IntuiText ERRBody = 
  848.     {
  849.     0,1, JAM2, 20,8, &TxtAt_Plain, (UBYTE *)"DISK ERROR:  Disk is", &ERRBody2 
  850.     };
  851.  
  852. struct IntuiText ERRPos = 
  853.     {
  854.     0,1, JAM2, 7,3, &TxtAt_Plain, "Retry", NULL 
  855.     };
  856.  
  857. struct IntuiText ERRNeg = 
  858.     {
  859.     0,1, JAM2, 7,3, &TxtAt_Plain, "Cancel", NULL 
  860.     };
  861.  
  862.  
  863. /***** Rewrite block?  Really? ******/
  864. struct IntuiText REWBody3 = 
  865.     {
  866.     0,1, JAM2, 20,28, &TxtAt_Plain,(UBYTE *) "boot sectors?", NULL 
  867.     };
  868.  
  869. struct IntuiText REWBody2 = 
  870.     {
  871.     0,1, JAM2, 20,18, &TxtAt_Plain,(UBYTE *) "rewrite that disk's boot", &REWBody3
  872.     };
  873.  
  874. struct IntuiText REWBody = 
  875.     {
  876.     0,1, JAM2, 20,8, &TxtAt_Plain,      (UBYTE *)"Are you sure you want to", &REWBody2 
  877.     };
  878.  
  879. struct IntuiText REWPos =
  880.     {
  881.     0,1, JAM2, 7,3, &TxtAt_Plain, "Yes", NULL 
  882.     };
  883.  
  884. struct IntuiText REWNeg = 
  885.     {
  886.     0,1, JAM2, 7,3, &TxtAt_Plain, "No!", NULL 
  887.     };
  888.  
  889.  
  890. /*********************Da Beginnin*************************/
  891.  
  892. main(argc, argv)
  893. int argc;
  894. char **argv;
  895. {
  896.  
  897. FromCLI = TRUE;
  898.  
  899. switch (argc)
  900.     {
  901.     case 0:
  902.         FromCLI = FALSE;
  903.         break;
  904.  
  905.     case 3:
  906.         NewWindow.LeftEdge = atoi(argv[1]);
  907.         NewWindow.TopEdge = atoi(argv[2]);
  908.         break;
  909.     };
  910.  
  911. WindowBig = FALSE;
  912.  
  913. /* Come on, folks, is intuition ever NOT going to be available???? */
  914. IntuitionBase = (struct IntuitionBase *)OpenLibrary("intuition.library",0);
  915.  
  916. /* Same with GfxBase.  If GfxBase is gone, we DESERVE to crash. */
  917. GfxBase = (struct GfxBase *)OpenLibrary("graphics.library",0);
  918.  
  919. /*  We use the same port/request through the whole program.  Works OK. */
  920. diskport = CreatePort(0,0);
  921. diskreq = CreateStdIO(diskport);
  922.  
  923. Window = OpenWindow(&NewWindow);
  924. if (Window == NULL) 
  925.     goto Quitter;    /* No memory to open little window! */
  926.  
  927. RP = Window->RPort;
  928.  
  929. /* This does some setup stuff, I guess, eh? */
  930. SetUp();
  931.  
  932. /*  Check for Byte Bandit, SCA, Revenge and ByteWarrior, etc. in RAM.  */
  933. CheckMemoryForViruses();
  934.  
  935. CheckBlock();
  936.  
  937. DoLittle();    /* The main loop.  Do Little.  Ya. */
  938.  
  939. Quitter:
  940. if (diskport != 0) DeletePort(diskport);
  941. if (diskreq != 0) DeleteStdIO(diskreq);
  942.  
  943. CloseLibrary(GfxBase);
  944. CloseLibrary(IntuitionBase);
  945. }            
  946.  
  947. /*********************/
  948. DoLittle()
  949. {
  950. register int Code;    /* for storing our IntuiMessage stuff */
  951. register int Class;
  952. register int KG2;    /* KeepGoing 2.  Another booleean. */
  953.  
  954. KG2 = TRUE;
  955.  
  956. SetAPen(RP, 1);
  957. SetBPen(RP, 0);
  958. SetDrMd(RP, JAM2);
  959.  
  960. while (KG2 == TRUE)
  961.     {
  962.     if (WindowBig == TRUE) DoStats();
  963.  
  964.     Goober:
  965.  
  966.     WaitPort(Window->UserPort);
  967.     Message = GetMsg(Window->UserPort);
  968.  
  969.     Class = Message->Class;
  970.     Code = Message->Code;
  971.     ReplyMsg(Message);
  972.     
  973.     if (Class == CLOSEWINDOW) 
  974.         {
  975.         KG2 = FALSE;
  976.         continue;
  977.         };
  978.  
  979.     if (Class == MOUSEBUTTONS)
  980.         if (Code == MENUDOWN)
  981.             { 
  982.             Class = VANILLAKEY; 
  983.             Code = 'i'; 
  984.             }
  985.             else goto Goober;
  986.  
  987.     if (Class == VANILLAKEY)
  988.         {
  989.         int flag;
  990.  
  991.         switch (Code)
  992.             {
  993.             case 'p':
  994.             case 'P':
  995.                 if (FromCLI == TRUE) Execute("NEWCLI", 0, 0);
  996.                 break;
  997.  
  998.             case 'w':
  999.             case 'W':
  1000.                 if (FromCLI == TRUE) Execute("NEWWSH", 0, 0);
  1001.                 break;
  1002.  
  1003.             case 'i':
  1004.             case 'I':
  1005.                 if (WindowBig == TRUE) WindowBig = FALSE;
  1006.                     else WindowBig = TRUE;
  1007.  
  1008.                 if (WindowBig == TRUE) 
  1009.                     {
  1010.                     if (Window->TopEdge > 80) MoveWindow(Window, 0, -Window->TopEdge);
  1011.                     SizeWindow(Window, 0, 100);
  1012.                     } else SizeWindow(Window, 0, -100);
  1013.  
  1014.                 WaitForNewSize();
  1015.                 break;
  1016.  
  1017.  
  1018.             case 'c':
  1019.             case 'C':
  1020.                 for (x=0; x<4; x++) ChangeCount[x] = 10000;
  1021.                 CheckBlock();
  1022.  
  1023.             default:
  1024.                 flag = ShowAscii(Code);
  1025.                 if (flag == 1) CheckBlock();
  1026.             };
  1027.         };
  1028.  
  1029.     if (Class == DISKINSERTED) CheckBlock();
  1030.     };
  1031.  
  1032. CloseWindow(Window);
  1033. }
  1034.  
  1035.  
  1036. /************************************************/
  1037. /* Opens trackdisk, finds out who's out there,  */
  1038. /* and sets Changecount up accordioningly.      */
  1039. /************************************************/
  1040. SetUp()
  1041. {
  1042. for (x = 0; x < 4; x++)    /* go thru all 4 possible drives */
  1043.     {
  1044.     ChangeCount[x] = 1000;
  1045.     error = OpenDevice(TDName,x,diskreq,0);
  1046.     if (error > 0) 
  1047.         {
  1048.         ChangeCount[x] = -1;
  1049.         } else CloseDevice(diskreq);
  1050.     };
  1051.  
  1052. }
  1053.  
  1054. /*********************************************************/
  1055. /* This routine returns which drive changed disks lately */
  1056. /*********************************************************/
  1057. WhoChanged()
  1058. {
  1059. int RetVal;    /* The value we'll return */
  1060.  
  1061. RetVal = -1;    /* return -1 if all else fails */
  1062. for (x = 0; x < 4; x++)
  1063.     {
  1064.     if (ChangeCount[x] == -1) continue;    /* no drive here */
  1065.     error = OpenDevice(TDName,x,diskreq,0);
  1066.     if (error > 0) continue;    /* no drive here */
  1067.     
  1068.     diskreq->io_Command = TD_CHANGESTATE;
  1069.     DoIO(diskreq);
  1070.     if (diskreq->io_Actual != 0) 
  1071.         {
  1072.         CloseDevice(diskreq);
  1073.         continue;
  1074.         };
  1075.  
  1076.     diskreq->io_Command = TD_CHANGENUM;
  1077.     DoIO(diskreq);
  1078.     if (diskreq->io_Actual != ChangeCount[x]) 
  1079.         {
  1080.         RetVal = x;
  1081.         ChangeCount[x] = diskreq->io_Actual;
  1082.         CloseDevice(diskreq);
  1083.         goto Out;
  1084.         };
  1085.  
  1086.     CloseDevice(diskreq);
  1087.     };
  1088.  
  1089. Out:;
  1090. return(RetVal);
  1091. }
  1092.  
  1093. /****************************************************************/
  1094. /*  Figures out which drive changed disks (using WhoChanged(),  */
  1095. /*  And checks it.  Calling this after every DISKINSERTED is OK.*/
  1096. /****************************************************************/
  1097. CheckBlock()
  1098. {
  1099. /*  How many register vars can I use, anyway? */
  1100. register int Sum, Bootable, Virus;
  1101. register int a, Unit;
  1102. int SCA, ByteWarrior, Revenge, BBandit;
  1103. int NorthStar, Obelisk;
  1104. register unsigned int *iptr;
  1105. unsigned int *ptr;
  1106.  
  1107. while ((Unit = WhoChanged()) != -1)
  1108.     {
  1109.     DisksChecked++;
  1110.  
  1111.     SCA = FALSE;
  1112.     BBandit = FALSE;
  1113.     Revenge = FALSE;
  1114.     ByteWarrior = FALSE;
  1115.     NorthStar = FALSE;
  1116.     Obelisk = FALSE;
  1117.  
  1118.     /* Unit # to open is returned by "WhoChanged()" up above. */
  1119.     if (Unit == -1) return;
  1120.     error = OpenDevice(TDName,Unit,diskreq,0);
  1121.     if (error > 0) return;
  1122.  
  1123.     error = ReadBlock();
  1124.     CloseDevice(diskreq);
  1125.     if (error == FALSE) return;
  1126.  
  1127.     ptr = diskbuffer;
  1128.     iptr = diskbuffer;
  1129.  
  1130.     if (iptr[0] != ID_DOS_DISK) return;    /* No DOS/0 */
  1131.  
  1132.     Sum = 0;
  1133.     for (a=0; a<256 /*1024/4 cuz we're dealing with ptr math now*/  ; a++)
  1134.         {
  1135.         LastSum = Sum;
  1136.         Sum = Sum + ptr[a];
  1137.         if (LastSum > Sum) Sum++;  /* took me a while to figger this out */
  1138.         }
  1139.  
  1140.     if (Sum != 0) 
  1141.         {
  1142.         return;    /* if it's not bootable, we DONT want it! */
  1143.         };
  1144.  
  1145.     ptr = &diskbuffer[4];
  1146.  
  1147.     if (diskbuffer[0x34] == 100)
  1148.         if (diskbuffer[0xc4] == 48)
  1149.             if (diskbuffer[0xc0] == 68)
  1150.                 if (diskbuffer[0xf1] == 7)
  1151.                     {
  1152.                     ByteWarriorCount++;
  1153.                     ByteWarrior = TRUE;
  1154.                     };
  1155.  
  1156.     if (diskbuffer[0x2b] == '9')
  1157.         if (diskbuffer[0x2c] == '.')
  1158.             if (diskbuffer[0x2d] == '8')
  1159.                 if (diskbuffer[0x2e] == '7')
  1160.                     {
  1161.                     ByteBanditCount++;
  1162.                     BBandit = TRUE;    /* 9.87 is part of BBandit Virus */
  1163.                     };
  1164.  
  1165.     /* check specifically for SCA virus */
  1166.     if (diskbuffer[8] == 'C')
  1167.         if (diskbuffer[9] == 'H')
  1168.             if (diskbuffer[10] == 'W')
  1169.                     {
  1170.                     SCA = TRUE;    /* CHW is part of SCA virus */
  1171.                     SCACount++;
  1172.                     };
  1173.  
  1174.     if (diskbuffer[0xe] == 'I')
  1175.         if (diskbuffer[0xf] == 'D')
  1176.             if (diskbuffer[0x10] == '9')
  1177.                 if (diskbuffer[0x1a6] == 'f')
  1178.                     {
  1179.                     Revenge= TRUE;
  1180.                     RevengeCount++;
  1181.                     };
  1182.  
  1183.     if (diskbuffer[0x12] == 78)
  1184.         if (diskbuffer[0x13c] == 68)        
  1185.             if (diskbuffer[0x18] == 83)
  1186.                 if (diskbuffer[0x19] == 116)
  1187.                     {
  1188.                     NorthStar = TRUE;
  1189.                     NorthStarCount++;
  1190.                     };
  1191.  
  1192.  
  1193.     if (diskbuffer[0x38] == 71)
  1194.         if (diskbuffer[0xbc] == 83)
  1195.             if (diskbuffer[0x1fb] == 100)
  1196.                 if (diskbuffer[0x2d] == 80)
  1197.                     {
  1198.                     Obelisk = TRUE;
  1199.                     ObeliskCount++;
  1200.                     };
  1201.  
  1202.     /* compare boot block with real boot block.  If it's not, notify God. */
  1203.     Virus = FALSE;
  1204.  
  1205.     for (x = 0; x < 39; x++) /* num of bytes in bootblock */
  1206.         {
  1207.         if (diskbuffer[8+x] != bootblock[8+x])
  1208.             {    
  1209.             Virus = TRUE;
  1210.             };
  1211.         };
  1212.  
  1213.     /* Oh no, a Virus! */
  1214.     if (Virus == TRUE) 
  1215.         {
  1216.         NBCTEXT[23] = '0'+Unit; /* change DF9: to real drive in text */
  1217.         TEXTPTR[23] = '0'+Unit;
  1218.         error = FALSE;
  1219.  
  1220.         if (SCA == TRUE)
  1221.             {
  1222.             /* OH NOOOOO, an SCA virus.  Wimpo virus, compared to BBandit 
  1223.                but it's a lot nicer code to read. */
  1224.             error = MyRequest(VN_SCA, 1);
  1225.             }
  1226.         else if (BBandit == TRUE)
  1227.             {
  1228.             /* The Byte Bandit Virus.  Tricky bugger, he WAS. Cheats, tho. */
  1229.             sprintf(CopyText, copystring, (diskbuffer[74]*256)+diskbuffer[75]);
  1230.             BuildITBodyText(VN_BYTEBANDIT, 1);
  1231.             error = AutoRequest(Window, &BBDiskbody, &SCAPos, &SCANeg, 0, 0, 380, 80);
  1232.             }
  1233.         else if (Revenge == TRUE)
  1234.             {
  1235.             /* Revenge virus.  X rated bugger, lot like Byte Bandit. */
  1236.             sprintf(CopyText, copystring, (diskbuffer[0x3f6]*256)+diskbuffer[0x3f7]);
  1237.             BuildITBodyText(VN_REVENGE, 1);
  1238.             error = AutoRequest(Window, &RevDiskbody, &SCAPos, &SCANeg, 0, 0, 380, 80);
  1239.             }
  1240.         else if (ByteWarrior == TRUE)
  1241.             {
  1242.             /* Byte Warrior.  Very 'friendly' virus.  Ez to get rid of.  */
  1243.             error = MyRequest(VN_BYTEWARRIOR, 1);
  1244.             }
  1245.         else if (NorthStar == TRUE)
  1246.             {
  1247.             /* NorthStar.  Nice virus - alerts you to others, ez to get rid of */
  1248.             error = MyRequest(VN_NORTHSTAR, 1);
  1249.             }
  1250.         else if (Obelisk == TRUE)
  1251.             {
  1252.             /* At least these guys are getting creative with their Graphics! */
  1253.             error = MyRequest(VN_OBELISK, 1);
  1254.             }
  1255.         else 
  1256.             {
  1257.             /* Probably just a custom boot block (or a new virus...) */
  1258.             error = AutoRequest(Window, &Body1, &SCAPos, &SCANeg, 0, 0, 320, 70);
  1259.             }
  1260.         if (error == TRUE) DoInstall(Unit); /* user wants it neutered. */
  1261.         };
  1262.     };  /* End of While Whochanged */
  1263. }
  1264.  
  1265. /********************************************/
  1266. /* This is where the boot code gets changed */
  1267. /********************************************/
  1268. DoInstall(un)
  1269. int un;    /* unit to write to */
  1270. {
  1271. register int x;
  1272. register int Sum;
  1273. register int err, a;
  1274.  
  1275. /* Rewrite disk?  Really?  */
  1276. error = AutoRequest(Window, &REWBody, &REWPos, &REWNeg, 0, 0, 320, 75);
  1277. if (error != TRUE) return;    /* user changed his brain. */
  1278.  
  1279. DisksInstalled++;
  1280.  
  1281. error = OpenDevice(TDName, un,diskreq,0);
  1282. if (error > 0) return;
  1283.  
  1284. trygain:
  1285.  
  1286. diskreq->io_Command = TD_PROTSTATUS;
  1287. DoIO(diskreq);        /* check if disk is write protected */
  1288.  
  1289. if (diskreq->io_Actual != 0)
  1290.     {
  1291.     error = AutoRequest(Window, &ERRBody, &ERRPos, &ERRNeg, 0, 0, 280, 75);
  1292.     if (error == TRUE) /* error is true or false, depending on user */
  1293.         {
  1294.         goto trygain;
  1295.         };
  1296.     CloseDevice(diskreq);
  1297.     return;    /* unrecoverable write protect error!!!!!!!!! */
  1298.     };
  1299.  
  1300.  
  1301. for (x = 0; x < 1024; x++)
  1302.     diskbuffer[x] = 0;    /* clear diskbuffer to zero.  clean. */
  1303.  
  1304. CopyMem(bootblock, diskbuffer, 50); /* Copy it over */
  1305.  
  1306. /* Write it ! */
  1307.  
  1308.     {
  1309.     error = 0;
  1310.     diskreq->io_Length = 1024; /* here we go! */
  1311.     diskreq->io_Data = &diskbuffer[0];  
  1312.     diskreq->io_Command = CMD_WRITE;
  1313.     diskreq->io_Offset = 0L;
  1314.     DoIO(diskreq);
  1315.     error = diskreq->io_Error;
  1316.     };
  1317.  
  1318. if (error < 19)
  1319.     {
  1320.     diskreq->io_Command = CMD_UPDATE;    /* flush buffer to disk */
  1321.     DoIO(diskreq);
  1322.     error = diskreq->io_Error;
  1323.     };
  1324.  
  1325. if (error < 19) 
  1326.     {
  1327.     diskreq->io_Length = 0;
  1328.     diskreq->io_Command = ETD_MOTOR;
  1329.     DoIO(diskreq);                /* turn off motor */
  1330.     error = diskreq->io_Error;
  1331.     };
  1332.  
  1333. CloseDevice(diskreq);
  1334.  
  1335. if (error > 19) 
  1336.     {
  1337.     SetWindowTitles(Window, "Error, Nothing Done.", -1);
  1338.     } 
  1339.     else
  1340.     {
  1341.     SetWindowTitles(Window, "Disk Healed.", -1);
  1342.     };
  1343.  
  1344. Delay(150);
  1345. SetWindowTitles(Window, TITLETEXT, -1);
  1346. }
  1347.  
  1348.  
  1349. /************************/
  1350.  
  1351. CheckMemoryForViruses()
  1352. {
  1353. int Temp;
  1354. struct ExecBase *ExecBase;
  1355. unsigned int *LongMemPointer;    /* Used for reading FROM memory */
  1356. unsigned short *loc;
  1357. unsigned int *ptr;
  1358. char linebuffer[80];
  1359.  
  1360. ExecBase = OpenLibrary("exec.library", 0);
  1361.  
  1362.  
  1363. /**************- Check for Byte Bandit (look at TD Vector) *************/
  1364. /*  (Byte Bandit isn't at a fixed location.  Depends on your RAM.      */
  1365.  
  1366. /* LongMemPointer = &trackdisk.device */
  1367. LongMemPointer = FindName(&ExecBase->DeviceList, TDName);
  1368. Temp = LongMemPointer;
  1369. Temp = Temp - 0x1c;
  1370. LongMemPointer = Temp; 
  1371. VirusBase = (*LongMemPointer) - 0x1b8;
  1372. LongMemPointer = VirusBase;
  1373.  
  1374. if (*LongMemPointer == ID_DOS_DISK)    /* klugo */
  1375.     {
  1376.     /* Ok, so we don't really remove it from memory, but we DO render
  1377.            it harmless. */
  1378. #asm
  1379.     xdef _VirusBase
  1380.     xref _geta4
  1381.     xref _LVODisable
  1382.     xref _LVOEnable
  1383.  
  1384.     jsr _geta4
  1385.  
  1386.     move.l 4,a6
  1387.     jsr _LVODisable(a6)
  1388.  
  1389.     move.l _VirusBase,a0
  1390.  
  1391.     move.w #$4e71,d0
  1392.  
  1393.     move.w d0,$aa(a0)    ; noops
  1394.     move.w d0,$ac(a0)    
  1395.     move.w d0,$ae(a0)
  1396.     move.w d0,$b0(a0)
  1397.  
  1398.     move.w #$6000,$1c2(a0)    ; change bxx to bra
  1399.  
  1400.     move.w #$6000,$2d2(a0)
  1401.  
  1402.     move.w #$4e75,$388(a0)
  1403.     move.w #0,$3ea(a0)
  1404.     move.w #0,(a0)
  1405.  
  1406.     jsr _LVOEnable(a6)
  1407.  
  1408. #endasm
  1409.     MyRequest(VN_BYTEBANDIT, 2);
  1410.     };
  1411.  
  1412. /****************- Look for Revenge Virus (at $7e000) ****************/
  1413. if (ExecBase->CoolCapture == 516192)
  1414.     {
  1415.     /* Fix the CoolCapture vector */
  1416.     ExecBase->CoolCapture = 0;
  1417.  
  1418. #asm
  1419.     xref _LVODisable
  1420.     xref _LVOEnable
  1421.  
  1422.     move.l 4,a6
  1423.     jsr _LVODisable(a6)
  1424.     
  1425.     ; Get rid of his DOS\0 in memory 
  1426.     lea $7e000,a0
  1427.     move.l #0,(a0)
  1428.  
  1429.     ; Patch his DoIO() wedge 
  1430.     move.w #$4ef9,$1e0(a0)
  1431.     move.w #$7,$1e2(a0)
  1432.     move.w #$e066,$1e4(a0)
  1433.  
  1434.     ; Patch his Interrupt wedge
  1435.     move.w #$4ef9,$2da(a0)
  1436.     move.w #$7,$2dc(a0)
  1437.     move.w #$e06c,$2de(a0)
  1438.  
  1439.     jsr _LVOEnable(a6)
  1440. #endasm
  1441.  
  1442.     MyRequest(VN_REVENGE, 2);
  1443.     };
  1444.  
  1445. /******************** See if SCA is in RAM ***************************/
  1446. if (ExecBase->CoolCapture == 0x7ec3e)
  1447.     {
  1448.     ExecBase->CoolCapture = 0;
  1449.     MyRequest(VN_SCA, 2);
  1450.     };
  1451.     
  1452. /***************** Check for Obelisk  *******************************/
  1453. if (ExecBase->CoolCapture == 0x7e86c)
  1454.     {
  1455.     ExecBase->CoolCapture = 0;
  1456.     ptr = 0x7e88a;
  1457.     Forbid();
  1458.     ptr[0] = 10;
  1459.     Permit();
  1460.     MyRequest(VN_OBELISK, 2);
  1461.     };
  1462.  
  1463. /******************** How about North Star? **************************/
  1464. if (ExecBase->CoolCapture == 0x7ec0e)
  1465.     {
  1466.     ExecBase->CoolCapture = 0;
  1467.     MyRequest(VN_NORTHSTAR, 2);
  1468.     };
  1469.  
  1470. /********************* Check for Byte Warrior ************************/
  1471. ptr = 0x7f800;
  1472. if ( ptr[0] == (0X444f5300) )
  1473.     {
  1474.     ptr = 0x7f954;
  1475.     if (ptr[0] == 0x4afc)
  1476.         {
  1477.         ptr[0] = 0;        /* Kill resident matchtag */
  1478.         
  1479. #asm
  1480.     xref    _LVOForbid
  1481.     xref    _LVOPermit
  1482.     xref    _Window
  1483.     xref     _BBMPos
  1484.     xref    _LVOAutoRequest
  1485.  
  1486.         move.l 4,a6
  1487.         jsr _LVOForbid(a6)
  1488.  
  1489.         lea $7f972,a0
  1490.         move.w #$4ef9,(a0)
  1491.         move.w #$fc,2(a0)
  1492.         move.w #$6dc,4(a0)
  1493.         ; jump right into the 1.2 ROMs. Ow.
  1494.         
  1495.         lea $7f800,a0
  1496.         move.l #0,(a0)
  1497.         jsr _LVOPermit(a6)
  1498.  
  1499. #endasm
  1500.         MyRequest(VN_BYTEWARRIOR, 2);
  1501.         };
  1502.     };
  1503.  
  1504. if (ExecBase->CoolCapture != 0)
  1505.     {
  1506.     sprintf(linebuffer, "Cool%s%x", CaptureStr, ExecBase->CoolCapture);
  1507.     if (MyRequest(linebuffer, 3) == TRUE) ExecBase->CoolCapture = 0;
  1508.     }
  1509.  
  1510. if (ExecBase->ColdCapture != 0)
  1511.     {
  1512.     sprintf(linebuffer, "Cold%s%x", CaptureStr, ExecBase->ColdCapture);
  1513.     if (MyRequest(linebuffer, 3) == TRUE) ExecBase->ColdCapture = 0;
  1514.     }
  1515.  
  1516. if (ExecBase->WarmCapture != 0)
  1517.     {
  1518.     sprintf(linebuffer, "Warm%s%x", CaptureStr, ExecBase->WarmCapture);
  1519.     if (MyRequest(linebuffer, 3) == TRUE) ExecBase->WarmCapture = 0;
  1520.     }
  1521.  
  1522.  
  1523. CloseLibrary(ExecBase);
  1524. }
  1525.  
  1526.  
  1527. /**************************************************************/
  1528. /*  This is the routine that displauys a block as ASCII text. */
  1529. /**************************************************************/
  1530. ShowAscii(key)
  1531. int key;
  1532. {
  1533. char linebuffer[80];
  1534. int drive;
  1535. int x,y;
  1536. int deltax, deltay;
  1537. int a,b;
  1538. int FLAG=0;
  1539.  
  1540. struct RastPort *RP;
  1541. RP = Window->RPort;
  1542.  
  1543. drive = key - '0';
  1544.  
  1545. if ((drive < 0) || (drive > 3) || (ChangeCount[drive] == -1)) return;
  1546.  
  1547. error = OpenDevice(TDName,drive,diskreq,0);
  1548. if (error > 0) return;
  1549.  
  1550. error = ReadBlock();
  1551.  
  1552. CloseDevice(diskreq);
  1553.  
  1554. if (error == FALSE) return;
  1555.  
  1556. /* save the amount we moved the window */
  1557. deltax = Window->LeftEdge;
  1558. deltay = Window->TopEdge;
  1559.  
  1560. MoveWindow(Window, -deltax, -deltay);
  1561.  
  1562. if (WindowBig == FALSE) SizeWindow(Window, 278, 160);
  1563.     else SizeWindow(Window, 278, 60);
  1564.  
  1565. WaitForNewSize();
  1566.  
  1567. SetAPen(RP, 3);
  1568. Move(RP, 14+(12*8), 165);
  1569. Text(RP, "Block 0", 7);
  1570. Move(RP, 324+(12*8), 165);
  1571. Text(RP, "Block 1", 7);
  1572. SetAPen(RP, 1);
  1573.  
  1574. text[2] = key;
  1575. SetWindowTitles(Window, text, -1);
  1576.  
  1577. x=0; y=0;
  1578.  
  1579. SetAPen(RP, 1);
  1580. SetDrMd(RP, JAM2);
  1581.  
  1582. for (a=0; a<512; a=a+32)
  1583.     {
  1584.     Move(RP, 10+(x*8), 20+(y*9));
  1585.     Text(RP, &diskbuffer[a], 32);
  1586.  
  1587.     Move(RP, 320+(x*8), 20+(y*9));
  1588.     Text(RP, &diskbuffer[a+512], 32);
  1589.     y++;
  1590.     };
  1591.  
  1592. Wait(1<<Window->UserPort->mp_SigBit);
  1593. Message = GetMsg(Window->UserPort);
  1594.  
  1595. /*  If a disk was inserted, we want CheckBlock() to happen later on some time */
  1596. if (Message->Class == DISKINSERTED) FLAG=1;
  1597. ReplyMsg(Message);
  1598.  
  1599. returner:
  1600. if (WindowBig == FALSE)
  1601.     SizeWindow(Window, -278, -160);
  1602.     else SizeWindow(Window, -278, -60);
  1603.  
  1604. SetWindowTitles(Window, TITLETEXT, -1);
  1605. WaitForNewSize();
  1606.  
  1607. /* deltas plus current position, in case dude moved the window */
  1608. MoveWindow(Window, deltax+(-Window->LeftEdge), deltay+(-Window->TopEdge));
  1609. Delay(2);
  1610. return(FLAG);
  1611. }
  1612.  
  1613.  
  1614. /*  
  1615.  When you do a SizeWindow() command, you have to wait for a NEWSIZE
  1616.  IntuiMessage before drawing in it.  That's all this routine does.
  1617.  */
  1618. WaitForNewSize()
  1619. {
  1620. while (TRUE)
  1621.     {
  1622.     WaitPort(Window->UserPort);
  1623.     Message = GetMsg(Window->UserPort);
  1624.     if (Message->Class != NEWSIZE)
  1625.         {
  1626.         ReplyMsg(Message);
  1627.         continue;
  1628.         };
  1629.     ReplyMsg(Message);
  1630.     break;
  1631.     };
  1632. }
  1633.  
  1634. /*
  1635.     type:
  1636.  
  1637.         1 == "is infected with the xxxx VIRUS!"
  1638.         2 == "somethin about virus in ram"
  1639.         3 == virus in cold/cool/warm capture 
  1640. */
  1641.  
  1642. BuildITBodyText(text, type)
  1643. char *text;
  1644. int type;
  1645. {
  1646. switch (type)
  1647.     {
  1648.     case 1:
  1649.         strcpy(ITBodyText, "infected with the `");
  1650.         strcat(ITBodyText, text);
  1651.         strcat(ITBodyText, "' VIRUS!");
  1652.         break;
  1653.     case 2:
  1654.         strcpy(ITBodyText, "NOTICE:  The `");
  1655.         strcat(ITBodyText, text);
  1656.         strcat(ITBodyText, "' VIRUS was found");
  1657.         break;
  1658.     };
  1659. }
  1660.  
  1661. /***** an attempt to save space *********/
  1662. MyRequest(string, type)
  1663. char *string;
  1664. int type;
  1665. {
  1666. if (type != 3)
  1667.     {
  1668.     BuildITBodyText(string, type);
  1669.     } else
  1670.     {
  1671.     Mem1.IText = string;
  1672.     };
  1673.  
  1674. if (type == 1) return(AutoRequest(Window, &GenericDiskBody, &SCAPos, &SCANeg, 0, 0, 380, 80));
  1675. if (type == 2) return(AutoRequest(Window, &GenericRAMBody, &BBMPos, &BBMPos, 0, 0, 395, 78));
  1676. if (type == 3) return(AutoRequest(Window, &Mem1, &Repair, &SCANeg, 0, 0, 395, 78));
  1677. }
  1678.  
  1679.  
  1680. /********* DoStats() **********/
  1681. DoStats()
  1682. {
  1683. char linebuffer[80];
  1684. char numbuf[30];
  1685.  
  1686. SetAPen(RP, 0);
  1687. RectFill(RP, 2, 11, 303, 107);
  1688. SetAPen(RP, 1);
  1689.  
  1690. sprintf(linebuffer, "  Disks Checked: %d", DisksChecked);
  1691. Out(20, linebuffer);
  1692.  
  1693. sprintf(linebuffer, "Disks Installed: %d", DisksInstalled);
  1694. Out(29, linebuffer);
  1695.  
  1696. Out(43, "    Viruses Found:");
  1697.  
  1698. PV(52, VN_SCA, SCACount);
  1699. PV(61, VN_BYTEBANDIT, ByteBanditCount);
  1700. PV(70, VN_NORTHSTAR, NorthStarCount);
  1701. PV(79, VN_BYTEWARRIOR, ByteWarriorCount);
  1702. PV(88, VN_REVENGE, RevengeCount);
  1703. PV(97, VN_OBELISK, ObeliskCount);
  1704. }
  1705.  
  1706. /****************** Ok, we're REALLY being chintzy here. */
  1707. PV(num, name, howmany)
  1708. int num;
  1709. char *name;
  1710. int howmany;
  1711. {
  1712. register int x;
  1713. char linebuffer[80];
  1714.  
  1715. sprintf(linebuffer, "%-12s: %d", name, howmany);
  1716. Out(num, linebuffer);
  1717. }
  1718.  
  1719. /***************************************** Cheap?  Me?  Nooooo....     */
  1720. /* This will write text to the column number in NUM, the text in Name. */
  1721. /*  Or something like that. ********************************************/
  1722. Out(num, name)
  1723. int num;
  1724. char *name;
  1725. {
  1726. Move(RP, 20, num);
  1727. Text(RP, name, strlen(name));
  1728. }
  1729. SHAR_EOF
  1730. cat << \SHAR_EOF > vx.asm
  1731. ;
  1732. ;
  1733. ;
  1734. ;  The ASSEMBLER portion of VirusX starts here.  This is where some of the
  1735. ;  more often called routines now live - in the smallness of Assembler.
  1736. ;
  1737. ;
  1738.     xref _geta4
  1739.     xref _diskreq
  1740.     xref _diskbuffer
  1741.     xref _LVODoIO
  1742.     xdef _ReadBlock
  1743.  
  1744. ;
  1745. ;  ReadBlock:  This will read the boot block.  Yay.
  1746. ;
  1747. _ReadBlock:
  1748.     movem.l d1/a0/a1/a4/a5/a6,-(sp)
  1749.     jsr _geta4
  1750.  
  1751.     move.l _diskreq,a0
  1752.     move.w #2,$1c(a0)         ; diskreq->io_Command = CMD_READ;
  1753.     lea _diskbuffer,a1
  1754.     move.l a1,d0
  1755.     move.l d0,$28(a0)         ; diskreq->io_Data = diskbuffer;
  1756.     move.l #(3*512),$24(a0)     ; diskreq->io_Length = 3*512;
  1757.     move.l #0,$2c(a0)        ; diskreq->io_Offset = 0;
  1758.     move.l 4,a6
  1759.  
  1760.     move.l _diskreq,a1
  1761.     jsr _LVODoIO(a6)        ; DoIO(diskreq);
  1762.  
  1763.     move.l _diskreq,a0
  1764.     cmp.b #0,$1f(a0)        ; check io_Error
  1765.     beq IsOkay            ; if (diskreq->io_Error > 0) return(FALSE);    /* disk error, lemme out */
  1766.  
  1767. ReturnError:
  1768.     move.l #0,d0            ; return error
  1769.     movem.l (sp)+,d1/a0/a1/a4/a5/a6
  1770.     rts
  1771.  
  1772. IsOkay:
  1773.     move.l #0,$24(a0)        ; diskreq->io_Length = 0;
  1774.     move.w #9,$1c(a0)        ; diskreq->io_Command = TD_MOTOR;
  1775.  
  1776.     move.l _diskreq,a1    
  1777.     move.l 4,a6
  1778.     jsr _LVODoIO(a6)        ; DoIO(diskreq);                /* turn off motor */
  1779.  
  1780.     move.l _diskreq,a0
  1781.     cmp.b #0,$1f(a0)
  1782.     bne ReturnError
  1783.  
  1784.     move.l #1,d0
  1785.     movem.l (sp)+,d1/a0/a1/a4/a5/a6
  1786.     rts
  1787. SHAR_EOF
  1788. #    End of shell archive
  1789. exit 0
  1790. -- 
  1791. Bob Page, U of Lowell CS Dept.  page@swan.ulowell.edu  ulowell!page
  1792. Have five nice days.
  1793.